/**
 * 
 */
package idv.takeshi.software.productline.bookstore.application.service.dto;

import java.util.Date;

import javax.validation.constraints.Digits;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;

import idv.takeshi.software.productline.bookstore.domain.model.deliveryservice.DeliveryService;
import idv.takeshi.software.productline.bookstore.domain.model.order.Invoice;
import idv.takeshi.software.productline.bookstore.domain.model.order.Order;
import idv.takeshi.software.productline.bookstore.domain.model.order.OrderFactory;
import idv.takeshi.software.productline.bookstore.domain.model.order.Payment;
import idv.takeshi.software.productline.bookstore.domain.model.shoppingcart.ShoppingCart;
import idv.takeshi.software.productline.bookstore.domain.model.useraccount.UserAccount;

import org.apache.commons.lang.Validate;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ReflectionToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * A data-transfer Object for Order model.
 * @author takeshi
 *
 */
public class OrderDto {
	
	private static final Log log = LogFactory.getLog(OrderDto.class);
	
	/**
	 * default constructor.
	 */
	public OrderDto() {}
	
	/**
	 * Fill default info into this DTO by given user account.
	 */
	public OrderDto(UserAccount userAccount) {
		Validate.notNull(userAccount, "userAccount shall always not be null");
		this.recipientName = userAccount.getUserName();
		this.recipientCellPhoneNumber = userAccount.getCellPhoneNumber();
		this.recipientAddress = userAccount.getContactAddress();
	}
	
	@Pattern(regexp = ".+")
	@NotNull
	private String paymentType;
	
	@Digits(fraction = 0, integer = 1)
	@NotNull
	private Integer deliveryServiceType;
	
	@Pattern(regexp = ".*")
	private String convenientStoreAddress;
	
	@Pattern(regexp = ".+")
	@NotNull
	private String invoiceType;
	
	@Pattern(regexp = "\\d*")
	private String invoiceUniformNumber;
	
	@Pattern(regexp = ".*")
	private String invoiceTitle;
	
	@Pattern(regexp = ".+")
	@NotNull
	private String recipientName;
	
	@Pattern(regexp = "\\d+")
	@NotNull
	private String recipientCellPhoneNumber;
	
	@Pattern(regexp = ".*")
	private String recipientAddress;
	
	@Pattern(regexp = ".*")
	private String recipientExtraRequirements;

	/**
	 * @return the paymentType
	 */
	public String getPaymentType() {
		return paymentType;
	}

	/**
	 * @param paymentType the paymentType to set
	 */
	public void setPaymentType(String paymentType) {
		this.paymentType = paymentType;
	}

	/**
	 * @return the deliveryServiceType
	 */
	public Integer getDeliveryServiceType() {
		return deliveryServiceType;
	}

	/**
	 * @param deliveryServiceType the deliveryServiceType to set
	 */
	public void setDeliveryServiceType(Integer deliveryServiceType) {
		this.deliveryServiceType = deliveryServiceType;
	}

	/**
	 * @return the convenientStoreAddress
	 */
	public String getConvenientStoreAddress() {
		return convenientStoreAddress;
	}

	/**
	 * @param convenientStoreAddress the convenientStoreAddress to set
	 */
	public void setConvenientStoreAddress(String convenientStoreAddress) {
		this.convenientStoreAddress = convenientStoreAddress;
	}

	/**
	 * @return the invoiceType
	 */
	public String getInvoiceType() {
		return invoiceType;
	}

	/**
	 * @param invoiceType the invoiceType to set
	 */
	public void setInvoiceType(String invoiceType) {
		this.invoiceType = invoiceType;
	}

	/**
	 * @return the invoiceUniformNumber
	 */
	public String getInvoiceUniformNumber() {
		return invoiceUniformNumber;
	}

	/**
	 * @param invoiceUniformNumber the invoiceUniformNumber to set
	 */
	public void setInvoiceUniformNumber(String invoiceUniformNumber) {
		this.invoiceUniformNumber = invoiceUniformNumber;
	}

	/**
	 * @return the invoiceTitle
	 */
	public String getInvoiceTitle() {
		return invoiceTitle;
	}

	/**
	 * @param invoiceTitle the invoiceTitle to set
	 */
	public void setInvoiceTitle(String invoiceTitle) {
		this.invoiceTitle = invoiceTitle;
	}

	/**
	 * @return the recipientName
	 */
	public String getRecipientName() {
		return recipientName;
	}

	/**
	 * @param recipientName the recipientName to set
	 */
	public void setRecipientName(String recipientName) {
		this.recipientName = recipientName;
	}

	/**
	 * @return the recipientCellPhoneNumber
	 */
	public String getRecipientCellPhoneNumber() {
		return recipientCellPhoneNumber;
	}

	/**
	 * @param recipientCellPhoneNumber the recipientCellPhoneNumber to set
	 */
	public void setRecipientCellPhoneNumber(String recipientCellPhoneNumber) {
		this.recipientCellPhoneNumber = recipientCellPhoneNumber;
	}

	/**
	 * @return the recipientAddress
	 */
	public String getRecipientAddress() {
		return recipientAddress;
	}

	/**
	 * @param recipientAddress the recipientAddress to set
	 */
	public void setRecipientAddress(String recipientAddress) {
		this.recipientAddress = recipientAddress;
	}

	/**
	 * @return the recipientExtraRequirements
	 */
	public String getRecipientExtraRequirements() {
		return recipientExtraRequirements;
	}

	/**
	 * @param recipientExtraRequirements the recipientExtraRequirements to set
	 */
	public void setRecipientExtraRequirements(String recipientExtraRequirements) {
		this.recipientExtraRequirements = recipientExtraRequirements;
	}
	
	/**
	 * Create a Order model by this DTO's properties and the given arguments.
	 * @param factory
	 * @param deliveryService
	 * @param convenientStoreDeliveryServiceId
	 * @param shoppingCart
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public Order createModel(OrderFactory orderFactory, 
			DeliveryService deliveryService, Integer convenientStoreDeliveryServiceId, 
			ShoppingCart shoppingCart){
		Order newOrder = null;
		try {
			
			Validate.notNull(orderFactory, "orderFactory shall always not be null");
			Validate.notNull(deliveryService, "deliveryService shall always not be null");
			Validate.notNull(convenientStoreDeliveryServiceId, 
					"convenientStoreDeliveryServiceId shall always not be null");
			Validate.notNull(shoppingCart, "shoppingCart shall always not be null");
			
			newOrder = orderFactory.newInstance(shoppingCart);
			newOrder.setDeliveryService(deliveryService);
			
			Date dateTime = new Date();
			Class paymentClass;
			paymentClass = Class.forName("idv.takeshi.software.productline.bookstore.domain.model.order." + this.paymentType);
		
			Payment payment = newOrder.addPayment(paymentClass);
			payment.setUpdateTime(dateTime);
			
			Class invoiceClass = Class.forName("idv.takeshi.software.productline.bookstore.domain.model.order." + this.invoiceType);
			Invoice invoice = newOrder.addInvoice(invoiceClass, this.invoiceTitle, this.invoiceUniformNumber);
			invoice.setUpdateTime(dateTime);
			
			newOrder.setRecipientName(this.recipientName);
			newOrder.setRecipientCellPhoneNumber(this.recipientCellPhoneNumber);
			newOrder.setExtraRequirements(this.recipientExtraRequirements);
			if(convenientStoreDeliveryServiceId.equals(newOrder.getDeliveryService().getId())){
				newOrder.setRecipientAddress(this.convenientStoreAddress);
			} else{
				newOrder.setRecipientAddress(this.recipientAddress);
			}
		
		} catch (ClassNotFoundException e) {
			String msg = "error occurs while generating new Order";
			log.error(msg, e);
			throw new RuntimeException(msg, e);
		}
		
		return newOrder;
	}
	
	/* (non-Javadoc)
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		return ReflectionToStringBuilder.toString(this, ToStringStyle.MULTI_LINE_STYLE);
	}
	
	
	
}
